/*-------------------------------------------------------------------------
 *
 * tlist.c
 *	  目标列表操作例程
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/optimizer/util/tlist.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/cost.h"
#include "optimizer/optimizer.h"
#include "optimizer/tlist.h"



/*
 * 测试表达式节点是否表示SRF调用。注意多个评估！
 *
 * 请注意，这仅用于split_pathtarget_at_srfs()；
 * 如果在其他地方使用，它几乎肯定会错误处理嵌套在表达式中的SRF。
 * 请改用expression_returns_set()。
 */
#define IS_SRF_CALL(node) \
	((IsA(node, FuncExpr) && ((FuncExpr *) (node))->funcretset) || \
	 (IsA(node, OpExpr) && ((OpExpr *) (node))->opretset))

/*
 * split_pathtarget_at_srfs()的数据结构。为了保持sortgroupref项目的唯一性
 * 即使它们在文本上相等，我们跟踪的不仅是裸表达式，而是表达式加上它们的sortgroupref索引。
 */
typedef struct
{
	Node	   *expr;			/* PathTarget的某个子表达式 */
	Index		sortgroupref;	/* 它的sortgroupref，如果没有则为0 */
} split_pathtarget_item;

typedef struct
{
	/* 这是一个裸表达式的列表： */
	List	   *input_target_exprs; /* 从输入中可用的exprs */
	/* 这些是split_pathtarget_items的列表列表： */
	List	   *level_srfs;		/* 每个级别要评估的SRF exprs */
	List	   *level_input_vars;	/* 每个级别需要的输入变量 */
	List	   *level_input_srfs;	/* 每个级别需要的输入SRFs */
	/* 这些是split_pathtarget_items的列表： */
	List	   *current_input_vars; /* 当前子表达式中需要的变量 */
	List	   *current_input_srfs; /* 当前子表达式中需要的SRFs */
	/* 当前split_pathtarget_walker遍历的辅助数据： */
	int			current_depth;	/* 当前子表达式中的最大SRF深度 */
	Index		current_sgref;	/* 当前子表达式的sortgroupref，或者0 */
} split_pathtarget_context;

static bool fc_split_pathtarget_walker(Node *fc_node,
									split_pathtarget_context *fc_context);
static void add_sp_item_to_pathtarget(PathTarget *fc_target,
									  split_pathtarget_item *fc_item);
static void add_sp_items_to_pathtarget(PathTarget *fc_target, List *fc_items);


/*****************************************************************************
 *		目标列表创建和搜索工具
 *****************************************************************************/

/*
 * tlist_member
 *	  查找给定目标列表中第一个与给定表达式相等的成员。 
 *	  如果没有这样的成员，结果为NULL。
 */
TargetEntry * tlist_member(Expr *fc_node, List *fc_targetlist)
{
	ListCell   *fc_temp;

	foreach(fc_temp, fc_targetlist)
	{
		TargetEntry *fc_tlentry = (TargetEntry *) lfirst(fc_temp);

		if (equal(fc_node, fc_tlentry->expr))
			return fc_tlentry;
	}
	return NULL;
}

/*
 * tlist_member_match_var
 *	  与上述相同，但我们仅根据varno/varattno/varlevelsup/vartype匹配提供的Var，而不是完全相等。
 *
 * 在某些情况下，我们无法确保完全的typmod匹配，因此需要此操作。
 * 为了安全起见，我们坚持要匹配vartype。
 */
static TargetEntry * fc_tlist_member_match_var(Var *fc_var, List *fc_targetlist)
{
	ListCell   *fc_temp;

	foreach(fc_temp, fc_targetlist)
	{
		TargetEntry *fc_tlentry = (TargetEntry *) lfirst(fc_temp);
		Var		   *fc_tlvar = (Var *) fc_tlentry->expr;

		if (!fc_tlvar || !IsA(fc_tlvar, Var))
			continue;
		if (fc_var->varno == fc_tlvar->varno &&
			fc_var->varattno == fc_tlvar->varattno &&
			fc_var->varlevelsup == fc_tlvar->varlevelsup &&
			fc_var->vartype == fc_tlvar->vartype)
			return fc_tlentry;
	}
	return NULL;
}

/*
 * add_to_flat_tlist
 *		向扁平化的目标列表添加更多项目（如果它们还不在其中）
 *
 * 'tlist'是扁平化的目标列表
 * 'exprs'是表达式的列表（通常，但不一定是，Vars）
 *
 * 返回扩展的目标列表。
 */
List * add_to_flat_tlist(List *fc_tlist, List *fc_exprs)
{
	int			fc_next_resno = list_length(fc_tlist) + 1;
	ListCell   *fc_lc;

	foreach(fc_lc, fc_exprs)
	{
		Expr	   *fc_expr = (Expr *) lfirst(fc_lc);

		if (!tlist_member(fc_expr, fc_tlist))
		{
			TargetEntry *fc_tle;

			fc_tle = makeTargetEntry(copyObject(fc_expr), 
/* 需要复制?? */
								  fc_next_resno++,
								  NULL,
								  false);
			fc_tlist = lappend(fc_tlist, fc_tle);
		}
	}
	return fc_tlist;
}


/*
 * get_tlist_exprs
 *		获取目标列表的表达式子树
 *
 * 忽略Resjunk列，除非includeJunk为真
 */
List * get_tlist_exprs(List *fc_tlist, bool fc_includeJunk)
{
	List	   *fc_result = NIL;
	ListCell   *fc_l;

	foreach(fc_l, fc_tlist)
	{
		TargetEntry *fc_tle = (TargetEntry *) lfirst(fc_l);

		if (fc_tle->resjunk && !fc_includeJunk)
			continue;

		fc_result = lappend(fc_result, fc_tle->expr);
	}
	return fc_result;
}


/*
 * count_nonjunk_tlist_entries
 *		如其所述...
 */
int count_nonjunk_tlist_entries(List *fc_tlist)
{
	int			fc_len = 0;
	ListCell   *fc_l;

	foreach(fc_l, fc_tlist)
	{
		TargetEntry *fc_tle = (TargetEntry *) lfirst(fc_l);

		if (!fc_tle->resjunk)
			fc_len++;
	}
	return fc_len;
}


/*
 * tlist_same_exprs
 *		检查两个目标列表是否包含相同的表达式
 *
 * 注意：此函数用于决定是否可以安全地将一个新的目标列表
 * 插入一个非投影能力的计划节点。显然，除非
 * 节点的目标列表显示它已经返回我们想要的列值，否则我们无法这样做。
 * 然而，我们可以忽略TargetEntry属性resname、ressortgroupref、
 * resorigtbl、resorigcol和resjunk，因为这些只是标签，不会影响
 * 节点计算的行值。（此外，如果我们不忽略它们，我们会经常
 * 失败于所期望的优化，因为规划器往往不在意在中间
 * 计划节点中使resname等有效。）注意在成功时，调用者仍然
 * 必须将所需的目标列表填入计划节点，否则它将没有所需的标签字段。
 */
bool tlist_same_exprs(List *fc_tlist1, List *fc_tlist2)
{
	ListCell   *fc_lc1,
			   *fc_lc2;

	if (list_length(fc_tlist1) != list_length(fc_tlist2))
		return false;			/* 长度不相同，因此无法匹配 */

	forboth(fc_lc1, fc_tlist1, fc_lc2, fc_tlist2)
	{
		TargetEntry *fc_tle1 = (TargetEntry *) lfirst(fc_lc1);
		TargetEntry *fc_tle2 = (TargetEntry *) lfirst(fc_lc2);

		if (!equal(fc_tle1->expr, fc_tle2->expr))
			return false;
	}

	return true;
}


/*
 * 目标列表是否具有与colTypes中列出的相同输出数据类型？
 *
 * 如果junkOK为真，则忽略Resjunk列；否则，Resjunk列的存在
 * 将始终导致“假”结果。
 *
 * 注意：目前没有调用方关心比较typmods。
 */
bool tlist_same_datatypes(List *fc_tlist, List *fc_colTypes, bool fc_junkOK)
{
	ListCell   *fc_l;
	ListCell   *fc_curColType = list_head(fc_colTypes);

	foreach(fc_l, fc_tlist)
	{
		TargetEntry *fc_tle = (TargetEntry *) lfirst(fc_l);

		if (fc_tle->resjunk)
		{
			if (!fc_junkOK)
				return false;
		}
		else
		{
			if (fc_curColType == NULL)
				return false;	/* 目标列表长于colTypes */
			if (exprType((Node *) fc_tle->expr) != lfirst_oid(fc_curColType))
				return false;
			fc_curColType = lnext(fc_colTypes, fc_curColType);
		}
	}
	if (fc_curColType != NULL)
		return false;			/* 目标列表短于colTypes */
	return true;
}

/*
 * 目标列表是否具有与colCollations中列出的相同显式排序规则？
 *
 * 与上面相同的逻辑，但用于排序规则。
 */
bool tlist_same_collations(List *fc_tlist, List *fc_colCollations, bool fc_junkOK)
{
	ListCell   *fc_l;
	ListCell   *fc_curColColl = list_head(fc_colCollations);

	foreach(fc_l, fc_tlist)
	{
		TargetEntry *fc_tle = (TargetEntry *) lfirst(fc_l);

		if (fc_tle->resjunk)
		{
			if (!fc_junkOK)
				return false;
		}
		else
		{
			if (fc_curColColl == NULL)
				return false;	/* 目标列表长于colCollations */
			if (exprCollation((Node *) fc_tle->expr) != lfirst_oid(fc_curColColl))
				return false;
			fc_curColColl = lnext(fc_colCollations, fc_curColColl);
		}
	}
	if (fc_curColColl != NULL)
		return false;			/* 目标列表短于colCollations */
	return true;
}

/*
 * apply_tlist_labeling
 *		将src_tlist的TargetEntry标签属性应用到dest_tlist
 *
 * 这对于将列名等重新附加到计划的最终输出
 * 目标列表中是有用的。
 */
void apply_tlist_labeling(List *fc_dest_tlist, List *fc_src_tlist)
{
	ListCell   *fc_ld,
			   *fc_ls;

	Assert(list_length(fc_dest_tlist) == list_length(fc_src_tlist));
	forboth(fc_ld, fc_dest_tlist, fc_ls, fc_src_tlist)
	{
		TargetEntry *fc_dest_tle = (TargetEntry *) lfirst(fc_ld);
		TargetEntry *fc_src_tle = (TargetEntry *) lfirst(fc_ls);

		Assert(fc_dest_tle->resno == fc_src_tle->resno);
		fc_dest_tle->resname = fc_src_tle->resname;
		fc_dest_tle->ressortgroupref = fc_src_tle->ressortgroupref;
		fc_dest_tle->resorigtbl = fc_src_tle->resorigtbl;
		fc_dest_tle->resorigcol = fc_src_tle->resorigcol;
		fc_dest_tle->resjunk = fc_src_tle->resjunk;
	}
}


/*
 * get_sortgroupref_tle
 *		找到与给定SortGroupRef索引匹配的目标列表条目，
 *		并返回它。
 */
TargetEntry * get_sortgroupref_tle(Index fc_sortref, List *fc_targetList)
{
	ListCell   *fc_l;

	foreach(fc_l, fc_targetList)
	{
		TargetEntry *fc_tle = (TargetEntry *) lfirst(fc_l);

		if (fc_tle->ressortgroupref == fc_sortref)
			return fc_tle;
	}

	elog(ERROR, "ORDER/GROUP BY expression not found in targetlist");
	return NULL;				/* 保持编译器安静 */
}

/*
 * get_sortgroupclause_tle
 *		通过ressortgroupref找到与给定SortGroupClause
 *		匹配的目标列表条目，并返回它。
 */
TargetEntry * get_sortgroupclause_tle(SortGroupClause *fc_sgClause,
						List *fc_targetList)
{
	return get_sortgroupref_tle(fc_sgClause->tleSortGroupRef, fc_targetList);
}

/*
 * get_sortgroupclause_expr
 *		通过ressortgroupref找到与给定SortGroupClause
 *		匹配的目标列表条目，并返回其表达式。
 */
Node * get_sortgroupclause_expr(SortGroupClause *fc_sgClause, List *fc_targetList)
{
	TargetEntry *fc_tle = get_sortgroupclause_tle(fc_sgClause, fc_targetList);

	return (Node *) fc_tle->expr;
}

/*
 * get_sortgrouplist_exprs
 *		给定SortGroupClauses列表，构建一个被引用的
 *		目标列表表达式列表。
 */
List * get_sortgrouplist_exprs(List *fc_sgClauses, List *fc_targetList)
{
	List	   *fc_result = NIL;
	ListCell   *fc_l;

	foreach(fc_l, fc_sgClauses)
	{
		SortGroupClause *fc_sortcl = (SortGroupClause *) lfirst(fc_l);
		Node	   *fc_sortexpr;

		fc_sortexpr = get_sortgroupclause_expr(fc_sortcl, fc_targetList);
		fc_result = lappend(fc_result, fc_sortexpr);
	}
	return fc_result;
}


/*****************************************************************************
 *		从SortGroupClauses列表中提取数据的函数
 *
 * 这些函数实际上不属于tlist.c，但它们与
 * 以上函数有些相关，并且似乎不值得拥有自己的文件。
 *****************************************************************************/

/*
 * get_sortgroupref_clause
 *		找到与给定SortGroupRef索引匹配的SortGroupClause，
 *		并返回它。
 */
SortGroupClause * get_sortgroupref_clause(Index fc_sortref, List *fc_clauses)
{
	ListCell   *fc_l;

	foreach(fc_l, fc_clauses)
	{
		SortGroupClause *fc_cl = (SortGroupClause *) lfirst(fc_l);

		if (fc_cl->tleSortGroupRef == fc_sortref)
			return fc_cl;
	}

	elog(ERROR, "ORDER/GROUP BY expression not found in list");
	return NULL;				/* 保持编译器安静 */
}

/*
 * get_sortgroupref_clause_noerr
 *		如上所述，但如果未找到，则返回NULL而不是抛出错误。
 */
SortGroupClause * get_sortgroupref_clause_noerr(Index fc_sortref, List *fc_clauses)
{
	ListCell   *fc_l;

	foreach(fc_l, fc_clauses)
	{
		SortGroupClause *fc_cl = (SortGroupClause *) lfirst(fc_l);

		if (fc_cl->tleSortGroupRef == fc_sortref)
			return fc_cl;
	}

	return NULL;
}

/*
 * extract_grouping_ops - 创建一个SortGroupClause列表的相等操作符OID数组
 */
Oid * extract_grouping_ops(List *fc_groupClause)
{
	int			fc_numCols = list_length(fc_groupClause);
	int			fc_colno = 0;
	Oid		   *fc_groupOperators;
	ListCell   *fc_glitem;

	fc_groupOperators = (Oid *) palloc(sizeof(Oid) * fc_numCols);

	foreach(fc_glitem, fc_groupClause)
	{
		SortGroupClause *fc_groupcl = (SortGroupClause *) lfirst(fc_glitem);

		fc_groupOperators[fc_colno] = fc_groupcl->eqop;
		Assert(OidIsValid(fc_groupOperators[fc_colno]));
		fc_colno++;
	}

	return fc_groupOperators;
}

/*
 * extract_grouping_collations - 创建一个SortGroupClause列表的分组列排序规则数组
 */
Oid * extract_grouping_collations(List *fc_groupClause, List *fc_tlist)
{
	int			fc_numCols = list_length(fc_groupClause);
	int			fc_colno = 0;
	Oid		   *fc_grpCollations;
	ListCell   *fc_glitem;

	fc_grpCollations = (Oid *) palloc(sizeof(Oid) * fc_numCols);

	foreach(fc_glitem, fc_groupClause)
	{
		SortGroupClause *fc_groupcl = (SortGroupClause *) lfirst(fc_glitem);
		TargetEntry *fc_tle = get_sortgroupclause_tle(fc_groupcl, fc_tlist);

		fc_grpCollations[fc_colno++] = exprCollation((Node *) fc_tle->expr);
	}

	return fc_grpCollations;
}

/*
 * extract_grouping_cols - 创建一个SortGroupClause列表的分组列resnos数组
 */
AttrNumber * extract_grouping_cols(List *fc_groupClause, List *fc_tlist)
{
	AttrNumber *fc_grpColIdx;
	int			fc_numCols = list_length(fc_groupClause);
	int			fc_colno = 0;
	ListCell   *fc_glitem;

	fc_grpColIdx = (AttrNumber *) palloc(sizeof(AttrNumber) * fc_numCols);

	foreach(fc_glitem, fc_groupClause)
	{
		SortGroupClause *fc_groupcl = (SortGroupClause *) lfirst(fc_glitem);
		TargetEntry *fc_tle = get_sortgroupclause_tle(fc_groupcl, fc_tlist);

		fc_grpColIdx[fc_colno++] = fc_tle->resno;
	}

	return fc_grpColIdx;
}

/*
 * grouping_is_sortable - 是否可以通过排序实现分组列表？
 *
 * 这很简单，因为解析器如果存在将会包含一个sortop。
 */
bool grouping_is_sortable(List *fc_groupClause)
{
	ListCell   *fc_glitem;

	foreach(fc_glitem, fc_groupClause)
	{
		SortGroupClause *fc_groupcl = (SortGroupClause *) lfirst(fc_glitem);

		if (!OidIsValid(fc_groupcl->sortop))
			return false;
	}
	return true;
}

/*
 * grouping_is_hashable - 是否可以通过哈希实现分组列表？
 *
 * 我们依赖解析器正确设置可哈希标志。
 */
bool grouping_is_hashable(List *fc_groupClause)
{
	ListCell   *fc_glitem;

	foreach(fc_glitem, fc_groupClause)
	{
		SortGroupClause *fc_groupcl = (SortGroupClause *) lfirst(fc_glitem);

		if (!fc_groupcl->hashable)
			return false;
	}
	return true;
}


/*****************************************************************************
 *		PathTarget操作函数
 *
 * PathTarget是完整目标列表的一个经过简化的版本；它
 * 省略了所有TargetEntry装饰，除了（可选的）sortgroupref数据，
 * 并添加了评估成本和输出数据宽度信息。
 *****************************************************************************/

/*
 * make_pathtarget_from_tlist
 *	  构造一个与给定目标列表等效的PathTarget。
 *
 * 这将成本和宽度字段留为零。大多数调用方希望
 * 使用create_pathtarget()，以便设置这些字段。
 */
PathTarget * make_pathtarget_from_tlist(List *fc_tlist)
{
	PathTarget *fc_target = makeNode(PathTarget);
	int			fc_i;
	ListCell   *fc_lc;

	fc_target->sortgrouprefs = (Index *) palloc(list_length(fc_tlist) * sizeof(Index));

	fc_i = 0;
	foreach(fc_lc, fc_tlist)
	{
		TargetEntry *fc_tle = (TargetEntry *) lfirst(fc_lc);

		fc_target->exprs = lappend(fc_target->exprs, fc_tle->expr);
		fc_target->sortgrouprefs[fc_i] = fc_tle->ressortgroupref;
		fc_i++;
	}

	/*
	 * 将波动性标记为未知。contain_volatile_functions函数
	 * 将在第一次以此PathTarget被调用时确定是否存在任何波动函数。
	 */
	fc_target->has_volatile_expr = VOLATILITY_UNKNOWN;

	return fc_target;
}

/*
 * make_tlist_from_pathtarget
 *	  从PathTarget构建目标列表。
 */
List * make_tlist_from_pathtarget(PathTarget *fc_target)
{
	List	   *fc_tlist = NIL;
	int			fc_i;
	ListCell   *fc_lc;

	fc_i = 0;
	foreach(fc_lc, fc_target->exprs)
	{
		Expr	   *fc_expr = (Expr *) lfirst(fc_lc);
		TargetEntry *fc_tle;

		fc_tle = makeTargetEntry(fc_expr,
							  fc_i + 1,
							  NULL,
							  false);
		if (fc_target->sortgrouprefs)
			fc_tle->ressortgroupref = fc_target->sortgrouprefs[fc_i];
		fc_tlist = lappend(fc_tlist, fc_tle);
		fc_i++;
	}

	return fc_tlist;
}



/*
 * copy_pathtarget
 *	  复制一个 PathTarget。
 *
 * 新的 PathTarget 有自己的 exprs 列表，但与旧的共享基础
 * 目标表达式树。
 */
PathTarget * copy_pathtarget(PathTarget *fc_src)
{
	PathTarget *fc_dst = makeNode(PathTarget);

	/* 复制标量字段 */
	memcpy(fc_dst, fc_src, sizeof(PathTarget));
	/* 浅拷贝表达式列表 */
	fc_dst->exprs = list_copy(fc_src->exprs);
	/* 如果有的话，复制sortgrouprefs（如果没有，memcpy处理了这个） */
	if (fc_src->sortgrouprefs)
	{
		Size		fc_nbytes = list_length(fc_src->exprs) * sizeof(Index);

		fc_dst->sortgrouprefs = (Index *) palloc(fc_nbytes);
		memcpy(fc_dst->sortgrouprefs, fc_src->sortgrouprefs, fc_nbytes);
	}
	return fc_dst;
}

/*
 * create_empty_pathtarget
 *	  创建一个空的（零列，零成本）PathTarget。
 */
PathTarget * create_empty_pathtarget(void)
{
	/* 这很简单，但我们不希望调用者硬编码这个... */
	return makeNode(PathTarget);
}

/*
 * add_column_to_pathtarget
 *		将目标列附加到PathTarget。
 *
 * 和make_pathtarget_from_tlist一样，我们留给调用者来更新
 * 成本和宽度字段。
 */
void add_column_to_pathtarget(PathTarget *fc_target, Expr *fc_expr, Index fc_sortgroupref)
{
	/* 更新exprs列表很简单... */
	fc_target->exprs = lappend(fc_target->exprs, fc_expr);
	/* ... sortgroupref数据就稍微复杂一些 */
	if (fc_target->sortgrouprefs)
	{
		int			fc_nexprs = list_length(fc_target->exprs);

		/* 这看起来可能效率不高，但实际上通常是便宜的 */
		fc_target->sortgrouprefs = (Index *)
			repalloc(fc_target->sortgrouprefs, fc_nexprs * sizeof(Index));
		fc_target->sortgrouprefs[fc_nexprs - 1] = fc_sortgroupref;
	}
	else if (fc_sortgroupref)
	{
		/* 将sortgroupref标记添加到先前未标记的目标 */
		int			fc_nexprs = list_length(fc_target->exprs);

		fc_target->sortgrouprefs = (Index *) palloc0(fc_nexprs * sizeof(Index));
		fc_target->sortgrouprefs[fc_nexprs - 1] = fc_sortgroupref;
	}

	/*
	 * 将has_volatile_expr重置为UNKNOWN。我们只是让
	 * contain_volatile_functions来再次正确设置这个。技术上
	 * 我们可以在这里节省一些工作，仅检查新的Expr，但
	 * 似乎更好在一个位置保持设置这个标志的逻辑，而不是
	 * 在这里重复逻辑。
	 */
	if (fc_target->has_volatile_expr == VOLATILITY_NOVOLATILE)
		fc_target->has_volatile_expr = VOLATILITY_UNKNOWN;
}

/*
 * add_new_column_to_pathtarget
 *		将目标列附加到PathTarget，但只有在它与
 *		任何现有目标表达式不相等时。
 *
 * 调用者不能指定sortgroupref，因为不清楚如何
 * 将其与现有列合并。
 *
 * 和make_pathtarget_from_tlist一样，我们留给调用者来更新
 * 成本和宽度字段。
 */
void add_new_column_to_pathtarget(PathTarget *fc_target, Expr *fc_expr)
{
	if (!list_member(fc_target->exprs, fc_expr))
		add_column_to_pathtarget(fc_target, fc_expr, 0);
}

/*
 * add_new_columns_to_pathtarget
 *		对列表中的每个元素应用add_new_column_to_pathtarget()。
 */
void add_new_columns_to_pathtarget(PathTarget *fc_target, List *fc_exprs)
{
	ListCell   *fc_lc;

	foreach(fc_lc, fc_exprs)
	{
		Expr	   *fc_expr = (Expr *) lfirst(fc_lc);

		add_new_column_to_pathtarget(fc_target, fc_expr);
	}
}

/*
 * apply_pathtarget_labeling_to_tlist
 *		将PathTarget中的任何sortgrouprefs应用于匹配的tlist条目
 *
 * 在这里，我们不假设tlist条目和
 * PathTarget是一一对应的。此函数的预期用途是处理
 * createplan.c决定使用其他tlist的情况，我们必须
 * 确定存在的匹配。
 */
void apply_pathtarget_labeling_to_tlist(List *fc_tlist, PathTarget *fc_target)
{
	int			fc_i;
	ListCell   *fc_lc;

	/* 如果PathTarget没有sortgrouprefs数据，则无事可做 */
	if (fc_target->sortgrouprefs == NULL)
		return;

	fc_i = 0;
	foreach(fc_lc, fc_target->exprs)
	{
		Expr	   *fc_expr = (Expr *) lfirst(fc_lc);
		TargetEntry *fc_tle;

		if (fc_target->sortgrouprefs[fc_i])
		{
			/*
			 * 对于Vars，使用tlist_member_match_var的弱匹配规则；
			 * 这使我们能够处理一些情况，其中一个返回集合的
			 * 函数已被内联，因此我们现在对其返回值有比
			 * 创建原始Var时更多的了解。否则，使用常规equal()
			 * 来查找匹配的TLE。（在当前使用中，实际上只需要
			 * Var情况；但似乎最好在非Var这里也有合理的行为。）
			 */
			if (fc_expr && IsA(fc_expr, Var))
				fc_tle = fc_tlist_member_match_var((Var *) fc_expr, fc_tlist);
			else
				fc_tle = tlist_member(fc_expr, fc_tlist);

			/*
			 * 如果没有地方用于sortgrouprefs标签，或者如果我们
			 * 必须标记同一列两次，则抱怨。（它已经具有
			 * 所需标签的情况可能无法发生，但我们可以允许它。）
			 */
			if (!fc_tle)
				elog(ERROR, "ORDER/GROUP BY expression not found in targetlist");
			if (fc_tle->ressortgroupref != 0 &&
				fc_tle->ressortgroupref != fc_target->sortgrouprefs[fc_i])
				elog(ERROR, "targetlist item has multiple sortgroupref labels");

			fc_tle->ressortgroupref = fc_target->sortgrouprefs[fc_i];
		}
		fc_i++;
	}
}


/*
 * split_pathtarget_at_srfs
 *		将给定的 PathTarget 拆分为多个级别，以安全地定位 SRFs
 *
 * 执行器只能处理出现在 ProjectSet 计划节点目标列表顶层的集返回函数。如果有任何 SRF 不在顶层，我们需要将评估拆分为多个计划级别，其中每个级别都满足此约束。此函数为每个级别创建适当的 PathTarget。
 *
 * 例如，考虑 tlist 表达式
 *		x + srf1(srf2(y + z))
 * 该表达式应按原样出现在顶层 PathTarget 中，但在其下方，我们必须有一个包含
 *		x, srf1(srf2(y + z))
 * 的 PathTarget，在下方又有一个包含
 *		x, srf2(y + z)
 * 的 PathTarget，在下方还有一个包含
 *		x, y, z
 * 的 PathTarget。当这些 tlists 被 setrefs.c 处理时，与下一个低层 tlist 的输出表达式相匹配的子表达式将被替换为 Vars，以便执行器获得的 tlists 看起来像
 *		Var1 + Var2
 *		Var1, srf1(Var2)
 *		Var1, srf2(Var2 + Var3)
 *		x, y, z
 * 这些都满足所需的属性。
 *
 * 另一个例子是
 *		srf1(x), srf2(srf3(y))
 * 这必须按原样出现在顶层 PathTarget 中，但在其下方，我们需要
 *		srf1(x), srf3(y)
 * 也就是说，必须在与其参数中的 SRF 嵌套深度相对应的级别计算每个 SRF。
 *
 * 在某些情况下，SRF 已在先前的计划级别中评估过，我们不应再次扩展它（也就是说，我们在目标中看到的内容已经意味着对下级子表达式的引用）。因此，如果 input_target 不为 NULL， 请勿扩展出现在 input_target 中的任何 tlist 表达式。
 *
 * 重要的是，我们要保留给定目标中出现的任何 sortgroupref 注释，特别是与 input_target 项目相匹配的表达式上的注释。
 *
 * 此函数的输出是两个并行列表，一个是 PathTargets 列表，另一个是整数列表的布尔标志，指示对应的 PathTarget 是否包含任何可评估的 SRF。列表按需要评估的顺序给出，"最低"的 PathTarget 在最前面。因此，最后一个列表项总是原始给定的 PathTarget，任何之前的项指示必须插入在其下方的评估级别。第一个列表项不得包含任何 SRF（除非是重复 input_target 项的 SRF），因为它通常将附加到无法评估 SRF 的计划节点。
 *
 * 注意：使用一个列表来表示标志可能看起来有些多余，因为只有少数可能的模式包含 SRF 的级别。但这种表示法使调用者与该知识解耦。
 */
void split_pathtarget_at_srfs(PlannerInfo *fc_root,
						 PathTarget *fc_target, PathTarget *fc_input_target,
						 List **fc_targets, List **fc_targets_contain_srfs)
{
	split_pathtarget_context fc_context;
	int			fc_max_depth;
	bool		fc_need_extra_projection;
	List	   *fc_prev_level_tlist;
	int			fc_lci;
	ListCell   *fc_lc,
			   *fc_lc1,
			   *fc_lc2,
			   *fc_lc3;

	/*
	 * planner.c 传递给我们的两个物理相同的目标并不罕见，在这种情况下，我们可以毫不费力地得出结论，所有表达式都可以从输入中获得。（下面的逻辑将得出相同的结论，但要繁琐得多。）
	 */
	if (fc_target == fc_input_target)
	{
		*fc_targets = list_make1(fc_target);
		*fc_targets_contain_srfs = list_make1_int(false);
		return;
	}

	/* 将任何 input_target 表达式传递给 split_pathtarget_walker() */
	fc_context.input_target_exprs = fc_input_target ? fc_input_target->exprs : NIL;

	/*
	 * 用空的零级列表初始化，并且没有后续级别。
	 * （注意：我们可以省略显式表示零级，因为它永远不会接收到任何 SRF，但然后我们必须在构建结果 PathTargets 时对此级别进行特殊处理。零级描述了将提供给输入计划节点的无 SRF PathTarget。）
	 */
	fc_context.level_srfs = list_make1(NIL);
	fc_context.level_input_vars = list_make1(NIL);
	fc_context.level_input_srfs = list_make1(NIL);

	/* 初始化我们将在所有目标表达式中累积的数据 */
	fc_context.current_input_vars = NIL;
	fc_context.current_input_srfs = NIL;
	fc_max_depth = 0;
	fc_need_extra_projection = false;

	/* 扫描 PathTarget 中的每个表达式以查找 SRF */
	fc_lci = 0;
	foreach(fc_lc, fc_target->exprs)
	{
		Node	   *fc_node = (Node *) lfirst(fc_lc);

		/* 告诉 split_pathtarget_walker 这个表达式的 sortgroupref */
		fc_context.current_sgref = get_pathtarget_sortgroupref(fc_target, fc_lci);
		fc_lci++;

		/*
		 * 找到此表达式中的所有 SRF 和 Var（以及类似 Var 的节点），并将它们输入到上下文结构中的适当列表中。
		 */
		fc_context.current_depth = 0;
		fc_split_pathtarget_walker(fc_node, &fc_context);

		/* 含有无 SRF 的表达式不再感兴趣 */
		if (fc_context.current_depth == 0)
			continue;

		/*
		 * 跟踪整个 PathTarget 的最大 SRF 嵌套深度。同时，如果该表达式确定了一个新的最大深度，我们不再关心先前表达式是否包含嵌套的 SRF；我们可以在最终的 ProjectSet 节点中处理它们所需的任何投影。
		 */
		if (fc_max_depth < fc_context.current_depth)
		{
			fc_max_depth = fc_context.current_depth;
			fc_need_extra_projection = false;
		}

		/*
		 * 如果任何最大深度的 SRF 并不在其表达式的顶层，我们将需要一个额外的 Result 节点来计算顶层标量表达式。
		 */
		if (fc_max_depth == fc_context.current_depth && !IS_SRF_CALL(fc_node))
			fc_need_extra_projection = true;
	}

	/*
	 * 如果我们没有找到需要评估的 SRF（也许它们都在 input_target 中，或者也许它们都被常量简化移除了），那么就不需要 ProjectSet；退出。
	 */
	if (fc_max_depth == 0)
	{
		*fc_targets = list_make1(fc_target);
		*fc_targets_contain_srfs = list_make1_int(false);
		return;
	}

	/*
	 * 如果我们不需要额外的投影步骤，则所需的顶层 Vars 和 SRF 输出可以添加到最后一个 level_input 列表中。如果我们需要，向列表中添加一个无 SRF 的级别。
	 */
	if (fc_need_extra_projection)
	{
		fc_context.level_srfs = lappend(fc_context.level_srfs, NIL);
		fc_context.level_input_vars = lappend(fc_context.level_input_vars,
										   fc_context.current_input_vars);
		fc_context.level_input_srfs = lappend(fc_context.level_input_srfs,
										   fc_context.current_input_srfs);
	}
	else
	{
		fc_lc = list_nth_cell(fc_context.level_input_vars, fc_max_depth);
		lfirst(fc_lc) = list_concat(lfirst(fc_lc), fc_context.current_input_vars);
		fc_lc = list_nth_cell(fc_context.level_input_srfs, fc_max_depth);
		lfirst(fc_lc) = list_concat(lfirst(fc_lc), fc_context.current_input_srfs);
	}

	
	*fc_targets = *fc_targets_contain_srfs = NIL;
	fc_prev_level_tlist = NIL;

	forthree(fc_lc1, fc_context.level_srfs,
			 fc_lc2, fc_context.level_input_vars,
			 fc_lc3, fc_context.level_input_srfs)
	{
		List	   *fc_level_srfs = (List *) lfirst(fc_lc1);
		PathTarget *fc_ntarget;

		if (lnext(fc_context.level_srfs, fc_lc1) == NULL)
		{
			fc_ntarget = fc_target;
		}
		else
		{
			fc_ntarget = create_empty_pathtarget();

			/*
			 * 这个目标实际上应该评估当前级别的任何 SRF，并且需要向前传播任何后续级别所需的 Vars，以及先前计算的并且后续级别所需的 SRF。
			 */
			add_sp_items_to_pathtarget(fc_ntarget, fc_level_srfs);
			for_each_cell(fc_lc, fc_context.level_input_vars,
						  lnext(fc_context.level_input_vars, fc_lc2))
			{
				List	   *fc_input_vars = (List *) lfirst(fc_lc);

				add_sp_items_to_pathtarget(fc_ntarget, fc_input_vars);
			}
			for_each_cell(fc_lc, fc_context.level_input_srfs,
						  lnext(fc_context.level_input_srfs, fc_lc3))
			{
				List	   *fc_input_srfs = (List *) lfirst(fc_lc);
				ListCell   *fc_lcx;

				foreach(fc_lcx, fc_input_srfs)
				{
					split_pathtarget_item *fc_item = lfirst(fc_lcx);

					if (list_member(fc_prev_level_tlist, fc_item->expr))
						add_sp_item_to_pathtarget(fc_ntarget, fc_item);
				}
			}
			set_pathtarget_cost_width(fc_root, fc_ntarget);
		}

		/*
		 * 将当前目标和是否计算 SRF 标志添加到输出列表中。
		 */
		*fc_targets = lappend(*fc_targets, fc_ntarget);
		*fc_targets_contain_srfs = lappend_int(*fc_targets_contain_srfs,
											(fc_level_srfs != NIL));

		/* 记住这一层的输出，以便进行下一次传递 */
		fc_prev_level_tlist = fc_ntarget->exprs;
	}
}

/*
 * 递归检查表达式以进行 split_pathtarget_at_srfs。
 *
 * 请注意，我们在这里不努力防止输出列表中的重复条目。重复项将在稍后去除。
 */
static bool fc_split_pathtarget_walker(Node *fc_node, split_pathtarget_context *fc_context)
{
	if (fc_node == NULL)
		return false;

	/*
	 * 匹配输入目标中已经计算的表达式的子表达式可以像 Var 一样处理（实际上在 setrefs.c 完成之后它将是 Var），即使它实际上是一个 SRF。将其记录为当前表达式所需，并忽略任何子结构。（尤其要注意，这保持了作为 sortgrouprefs 出现在输入目标中的任何表达式的身份。）
	 */
	if (list_member(fc_context->input_target_exprs, fc_node))
	{
		split_pathtarget_item *fc_item = palloc(sizeof(split_pathtarget_item));

		fc_item->expr = fc_node;
		fc_item->sortgroupref = fc_context->current_sgref;
		fc_context->current_input_vars = lappend(fc_context->current_input_vars,
											  fc_item);
		return false;
	}

	/*
	 * Vars 和类似 Var 的构造也应该从输入中获得。我们假设这些构造不能包含任何 SRF（如果包含，则会因 SRF 的放置不当而导致执行器失败）。
	 */
	if (IsA(fc_node, Var) ||
		IsA(fc_node, PlaceHolderVar) ||
		IsA(fc_node, Aggref) ||
		IsA(fc_node, GroupingFunc) ||
		IsA(fc_node, WindowFunc))
	{
		split_pathtarget_item *fc_item = palloc(sizeof(split_pathtarget_item));

		fc_item->expr = fc_node;
		fc_item->sortgroupref = fc_context->current_sgref;
		fc_context->current_input_vars = lappend(fc_context->current_input_vars,
											  fc_item);
		return false;
	}

	/*
	 * 如果这是一个 SRF，递归检查其输入，确定其级别，并在输出列表中做相应的条目。
	 */
	if (IS_SRF_CALL(fc_node))
	{
		split_pathtarget_item *fc_item = palloc(sizeof(split_pathtarget_item));
		List	   *fc_save_input_vars = fc_context->current_input_vars;
		List	   *fc_save_input_srfs = fc_context->current_input_srfs;
		int			fc_save_current_depth = fc_context->current_depth;
		int			fc_srf_depth;
		ListCell   *fc_lc;

		fc_item->expr = fc_node;
		fc_item->sortgroupref = fc_context->current_sgref;

		fc_context->current_input_vars = NIL;
		fc_context->current_input_srfs = NIL;
		fc_context->current_depth = 0;
		fc_context->current_sgref = 0; /* 子表达式不是 sortgroup 项 */

		(void) expression_tree_walker(fc_node, fc_split_pathtarget_walker,
									  (void *) fc_context);

		/* 深度比下面的任何 SRF 多一个 */
		fc_srf_depth = fc_context->current_depth + 1;

		/* 如果是新记录深度，初始化另一个输出列表的级别 */
		if (fc_srf_depth >= list_length(fc_context->level_srfs))
		{
			fc_context->level_srfs = lappend(fc_context->level_srfs, NIL);
			fc_context->level_input_vars = lappend(fc_context->level_input_vars, NIL);
			fc_context->level_input_srfs = lappend(fc_context->level_input_srfs, NIL);
		}

		/* 将此 SRF 记录为需要在适当级别进行评估 */
		fc_lc = list_nth_cell(fc_context->level_srfs, fc_srf_depth);
		lfirst(fc_lc) = lappend(lfirst(fc_lc), fc_item);

		/* 将其输入记录为在同一层级下所需 */
		fc_lc = list_nth_cell(fc_context->level_input_vars, fc_srf_depth);
		lfirst(fc_lc) = list_concat(lfirst(fc_lc), fc_context->current_input_vars);
		fc_lc = list_nth_cell(fc_context->level_input_srfs, fc_srf_depth);
		lfirst(fc_lc) = list_concat(lfirst(fc_lc), fc_context->current_input_srfs);

		/*
		 * 恢复调用者级别状态并更新以反映此 SRF 的存在。注意，我们报告 SRF 本身被视为需要评估周围表达式。
		 */
		fc_context->current_input_vars = fc_save_input_vars;
		fc_context->current_input_srfs = lappend(fc_save_input_srfs, fc_item);
		fc_context->current_depth = Max(fc_save_current_depth, fc_srf_depth);

		/* 我们在这里完成了 */
		return false;
	}

	/*
	 * 否则，该节点是一个标量（非集合）表达式，因此递归检查其输入。
	 */
	fc_context->current_sgref = 0; /* 子表达式不是 sortgroup 项 */
	return expression_tree_walker(fc_node, fc_split_pathtarget_walker,
								  (void *) fc_context);
}

/*
 * 向 PathTarget 添加一个 split_pathtarget_item，除非已经存在匹配项。这类似于 add_new_column_to_pathtarget，但允许处理 sortgrouprefs。具有零 sortgroupref 的项可以与具有 sortgroupref 的项合并，从而获取后者的 sortgroupref。
 *
 * 请注意，我们不担心可能将重复的 sortgrouprefs 添加到 PathTarget。这将是坏事，但除非传递给 split_pathtarget_at_srfs 的目标已经存在重复，否则这应该是不可能的。只要它没有，我们最多可以有一个带有任何特定非零 sortgroupref 的 split_pathtarget_item。
 */
static void add_sp_item_to_pathtarget(PathTarget *fc_target, split_pathtarget_item *fc_item)
{
	int			fc_lci;
	ListCell   *fc_lc;

	/*
	 * 查找一个已经存在的项，该项相等且没有冲突的 sortgroupref。
	 */
	fc_lci = 0;
	foreach(fc_lc, fc_target->exprs)
	{
		Node	   *fc_node = (Node *) lfirst(fc_lc);
		Index		fc_sgref = get_pathtarget_sortgroupref(fc_target, fc_lci);

		if ((fc_item->sortgroupref == fc_sgref ||
			 fc_item->sortgroupref == 0 ||
			 fc_sgref == 0) &&
			equal(fc_item->expr, fc_node))
		{
			/* 找到匹配项。如果它有一个，则分配项的 sortgroupref。 */
			if (fc_item->sortgroupref)
			{
				if (fc_target->sortgrouprefs == NULL)
				{
					fc_target->sortgrouprefs = (Index *)
						palloc0(list_length(fc_target->exprs) * sizeof(Index));
				}
				fc_target->sortgrouprefs[fc_lci] = fc_item->sortgroupref;
			}
			return;
		}
		fc_lci++;
	}

	/*
	 * 没有匹配项，因此将项添加到 PathTarget。为了安全起见，复制表达式。
	 */
	add_column_to_pathtarget(fc_target, (Expr *) copyObject(fc_item->expr),
							 fc_item->sortgroupref);
}

/*
 * 将 add_sp_item_to_pathtarget 应用于列表的每个元素。
 */
static void add_sp_items_to_pathtarget(PathTarget *fc_target, List *fc_items)
{
	ListCell   *fc_lc;

	foreach(fc_lc, fc_items)
	{
		split_pathtarget_item *fc_item = lfirst(fc_lc);

		add_sp_item_to_pathtarget(fc_target, fc_item);
	}
}
